import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';

import { SELECTED_KEY } from './selectedKey.const';


@Injectable()
export class TableSelectService {

  /** Selected key to be appended on selected data. */
  selectedKey = SELECTED_KEY;

  /** Selected data's observable. */
  selectChangeObservable: Observable<any>;

  private data: any[] = [];

  private selectSubject = new Subject<any>();

  private muteRows = [];

  get selectableRowData(): any {
    return this.data
    .filter((datum) => this.muteRows.indexOf(datum) === -1);
  }

  constructor() {
    this.selectChangeObservable = this.selectSubject.asObservable();
  }

  /** Get if the row is selected. */
  getRowSelected(rowData: any): boolean {
    return rowData && rowData[this.selectedKey];
  }

  /** Get if all data is selected. */
  isAllSelected(): boolean {
    if (this.selectableRowData.length === 0) {
      return false;
    }

    return !this.selectableRowData
    .map((datum) => datum[this.selectedKey])
    .filter((selected) => selected === false || selected === undefined)
    .length;
  }

  /** Batch select or unselect. */
  batchSelect(selected: boolean) {
    if (this.selectableRowData.length === 0) {
      return;
    }

    this.selectableRowData
    .forEach((datum) => {
      datum[this.selectedKey] = selected;
      return datum;
    });
    this.emitSelectChange();
  }

  /** Select or unselect a data. */
  select(rowData: any, selected?: boolean) {
    if (selected !== undefined) {
      rowData[this.selectedKey] = selected;
    } else {
      rowData[this.selectedKey] = !rowData[this.selectedKey];
    }
    this.emitSelectChange();
  }

  /** Mute or unmute a data. */
  muteSelect(rowData: any, mute: boolean) {
    const muteIdx = this.muteRows.indexOf(rowData);
    if (muteIdx === -1 && mute) {
      this.muteRows.push(rowData);
    } else if (muteIdx > -1 && !mute) {
      this.muteRows.splice(muteIdx, 1);
    }
  }

  /** Register data. */
  register(rowData: any) {
    this.data.push(rowData);
  }

  /** Unregister data. */
  unregister(rowData: any) {
    const idx = this.data.indexOf(rowData);
    this.data.splice(idx, 1);
    const muteIdx = this.muteRows.indexOf(rowData);
    if (muteIdx !== -1) {
      this.muteRows.splice(muteIdx, 1);
    }
  }

  private emitSelectChange() {
    const selectedData = this.data.filter((d) => d[this.selectedKey]);
    this.selectSubject.next(selectedData);
  }
}
